/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2018-11-7      SummerGift   first version
 */

#include "drv_common.h"

#ifdef RT_USING_SERIAL
#include "drv_usart.h"
#endif

//使用finsh组件才会使用这段代码，这里保留即可
#ifdef RT_USING_FINSH
#include <finsh.h>
static void reboot(uint8_t argc, char **argv)
{
    rt_hw_cpu_reset();
}
FINSH_FUNCTION_EXPORT_ALIAS(reboot, __cmd_reboot, Reboot System);
#endif /* RT_USING_FINSH */

//系统滴答定时器初始化，HAL库相关函数要改成GD使用的同功能函数,使用其他芯片的朋友酌情参考
/* SysTick configuration */
void rt_hw_systick_init(void)
{
    systick_config(RT_TICK_PER_SECOND); //根据RT_TICK_PER_SECOND宏来配置RT-Thread的心跳频率
    nvic_irq_enable((uint8_t)SysTick_IRQn, 0, 0); //滴答定时器优先级最高
}

//滴答定时器的中断服务函数，里面有RT-Thread自己的中断回调，也有HAL库的中断回调，Demo这里不用HAL库因此会去掉HAL库的回调
/**
 * This is the timer interrupt service routine.
 *
 */
void SysTick_Handler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    delay_decrement(); //模仿HAL库的ms级等待写的中断回调函数，不需要ms级死等delay的可以去掉
    rt_tick_increase();

    /* leave interrupt */
    rt_interrupt_leave();
}

/**
 * This function will delay for some us.
 *
 * @param us the delay time of us
 */
void rt_hw_us_delay(rt_uint32_t us)
{
    rt_uint32_t ticks;
    rt_uint32_t told, tnow, tcnt = 0;
    rt_uint32_t reload = SysTick->LOAD;

    ticks = us * reload / (1000000 / RT_TICK_PER_SECOND);
    told = SysTick->VAL;
    while (1)
    {
        tnow = SysTick->VAL;
        if (tnow != told)
        {
            if (tnow < told)
            {
                tcnt += told - tnow;
            }
            else
            {
                tcnt += reload - tnow + told;
            }
            told = tnow;
            if (tcnt >= ticks)
            {
                break;
            }
        }
    }
}

//这个函数是重头戏，会做适量修改，主要是替换HAL库的函数为我们GD的库所使用的，其他地方不需要改动。
/**
 * This function will initial STM32 board.
 */
RT_WEAK void rt_hw_board_init()
{
#ifdef SCB_EnableICache
    /* Enable I-Cache---------------------------------------------------------*/
    SCB_EnableICache();
#endif

#ifdef SCB_EnableDCache
    /* Enable D-Cache---------------------------------------------------------*/
    SCB_EnableDCache();
#endif
	
    /* SystemInit() function is called at the beginning of the program */
    SystemInit(); //GD外设库的系统初始化函数实际上，GD的库类似以前的ST标准库，这个函数在上电复位中断中已经被执行过一次
                  //并且这个函数里面已经包含了时钟初始化，因此不需要再调用时钟初始化。这里再次显性的调用一次。
    	
    /* System clock initialization */
    rt_hw_systick_init(); //滴答定时器初始化

    
    /* enable GPIO clock */
    rcu_periph_clock_enable(RCU_AF);
    rcu_periph_clock_enable(RCU_GPIOB);
    gpio_pin_remap_config(GPIO_USART0_REMAP,ENABLE);
    /* connect port to USART0_Tx */
    gpio_init(GPIOB,GPIO_MODE_AF_PP,GPIO_OSPEED_MAX,GPIO_PIN_6);
    /* connect port to USART0_Rx */
    gpio_init(GPIOB,GPIO_MODE_IPU,GPIO_OSPEED_MAX,GPIO_PIN_7);
    /* enable USART0 clock */
    rcu_periph_clock_enable(RCU_USART0);
    /* config USART0 */
    usart_deinit(USART0);
    usart_baudrate_set(USART0,115200);
    usart_parity_config(USART0,USART_PM_NONE);
    usart_word_length_set(USART0,USART_WL_8BIT);
    usart_stop_bit_set(USART0,USART_STB_1BIT);
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
    usart_hardware_flow_rts_config(USART0,USART_RTS_DISABLE);
    usart_hardware_flow_cts_config(USART0,USART_CTS_DISABLE);    
    /* enalbe USART0 */
    usart_enable(USART0);
    usart_flag_clear(USART0,USART_FLAG_TC);  
    
    /* Heap initialization */
#if defined(RT_USING_HEAP) 
    rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
#endif

    /* Pin driver initialization is open by default */
#ifdef RT_USING_PIN
    rt_hw_pin_init();
#endif

    /* USART driver initialization is open by default */
#ifdef RT_USING_SERIAL
    rt_hw_usart_init();
#endif

    /* Set the shell console output device */
#ifdef RT_USING_CONSOLE
    rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif

    /* Board underlying hardware initialization */
#ifdef RT_USING_COMPONENTS_INIT
    rt_components_board_init();
#endif
}

//添加一部分内容：不使用设备驱动的时候，控制台的输出（其实就是串口打印，根据大家实际芯片和库函数修改，能完成将str这个字符串打印出来即可）
void rt_hw_console_output(const char *str)
{
    while(*str != '\0')
    {
        if(*str == '\n' && *(str-1) != '\r')
        {
            usart_data_transmit(USART0,(uint32_t)'\r');
            while(usart_flag_get(USART0,USART_FLAG_TC) == RESET);
            usart_flag_clear(USART0,USART_FLAG_TC);
        }
        usart_data_transmit(USART0,(uint32_t)(*str++));
        while(usart_flag_get(USART0,USART_FLAG_TC) == RESET);
        usart_flag_clear(USART0,USART_FLAG_TC);
    }
}
